package cz.cvut.fel.taskpro.data.manager;


import cz.cvut.fel.taskpro.data.entity.GroupTaskPro;
import cz.cvut.fel.taskpro.data.entity.Kantor;
import cz.cvut.fel.taskpro.data.entity.Student;
import cz.cvut.fel.taskpro.data.entity.Subject;
import cz.cvut.fel.taskpro.data.entity.TaskProUser;
import cz.cvut.fel.taskpro.data.entity.Team;
import cz.cvut.fel.taskpro.data.imanager.IUserData;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;


/**
 * This statelss EJB specify database responsible implementation action of data manager,
 * which is responsible for working with users.
 * Implements #{@link IUserData}
 *
 * @author Tom
 * @version 1.0.0. beta
 */
@Stateless
public class UserData extends ObjectManager implements IUserData {

    public UserData() {
    }

    @Override
    public void addUser(TaskProUser userToAdd) {
        super.add(userToAdd);
    }

    @Override
    public void removeUser(TaskProUser userToRemove) {
        remove(userToRemove);
    }

    @Override
    public TaskProUser findByLogin(String login) {

        TaskProUser result = null;
        Query q = em.createNamedQuery("TaskProUser.findByLogin");
        q.setParameter("login", login);
        List<Object> res = q.getResultList();
        if (res.size() == 1) {
            result = (TaskProUser) res.get(0);
        }
        return result;
    }

    @Override
    public void updateUser(TaskProUser userToUpdate) {
        update(userToUpdate);
    }
    @Override
    public List<TaskProUser> getAllUsers() {
        Query q = em.createNamedQuery("TaskProUser.all");
        List<TaskProUser> ul = q.getResultList();
        return ul;
    }

    
    @Override
    public List<Student> getAllStudents() {
        Query q = em.createNamedQuery("Student.all");
        List<Student> ls = q.getResultList();
        return ls;
    }

    @Override
    public List<Kantor> getAllKantors() {
        Query q = em.createNamedQuery("Kantor.all");
        List<Kantor> lk = q.getResultList();
        return lk;
    }

    @Override
    public List<Student> getAllStudentByKantor(Kantor k) {
        Query q = em.createNamedQuery("Student.findByKantor");
        q.setParameter("kantor", k);
        List<Student> resultList = q.getResultList();      
        return resultList;      
    }

    @Override
    public List<Student> getStudentsByGroup(List<GroupTaskPro> groups) {
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<Student> groupQuery = cb.createQuery(Student.class);
        Root<Student> groupQueryRoot = groupQuery.from(Student.class);
        Join<GroupTaskPro,Student> studentGroup=groupQueryRoot.join("mGroups");
        List<Predicate> studentPredicate = new ArrayList<Predicate>();
            Iterator groupIt = groups.iterator();
            while (groupIt.hasNext()) {
                GroupTaskPro currGroup= (GroupTaskPro) groupIt.next();
                studentPredicate.add(cb.equal(studentGroup,currGroup));
            }       
        Predicate studentPr = cb.or(studentPredicate.toArray(new Predicate[0]));
        groupQuery.distinct(true);
        groupQuery.where(studentPr);
        groupQuery.orderBy(cb.asc(groupQueryRoot.get("surname")));
        TypedQuery typedQuery = em.createQuery(groupQuery);
        List<Student> resultList = typedQuery.getResultList();
        return resultList;
    }

    @Override
    public List<Student> getStudentsByGroup(GroupTaskPro group) {
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<Student> groupQuery = cb.createQuery(Student.class);
        Root<Student> groupQueryRoot = groupQuery.from(Student.class);
        Predicate studentPr = cb.equal(groupQueryRoot.get("mGroups"), group);
        groupQuery.distinct(true);
        groupQuery.where(studentPr);
        groupQuery.orderBy(cb.asc(groupQueryRoot.get("surname")));
        TypedQuery typedQuery = em.createQuery(groupQuery);
        List<Student> resultList = typedQuery.getResultList();
        return resultList;
    }

    @Override
    public List<Student> getStudentsByTeam(List<Team> teams) {
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<Student> teamQuery = cb.createQuery(Student.class);
        Root<Student> teamQueryRoot = teamQuery.from(Student.class);
        List<Predicate> studentPredicate = new ArrayList<Predicate>();
        Join<Team, Student> teamStudent = teamQueryRoot.join("team");  
        teamQuery.select(teamQueryRoot);
            Iterator teamIt = teams.iterator();
            while (teamIt.hasNext()) {
                Team currTeam = (Team) teamIt.next();
                studentPredicate.add(cb.equal(teamStudent, currTeam));
            }
        Predicate studentPr = cb.or(studentPredicate.toArray(new Predicate[0]));
        teamQuery.distinct(true);
        teamQuery.where(studentPr);
        teamQuery.orderBy(cb.asc(teamQueryRoot.get("surname")));
        TypedQuery typedQuery = em.createQuery(teamQuery);
        List<Student> resultList = typedQuery.getResultList();
        return resultList;
    }

    @Override
    public TaskProUser findByEmail(String email) {
        Query q = em.createNamedQuery("TaskProUser.findByEmail");
        q.setParameter("email", email);
        List<Object> res = q.getResultList();
        TaskProUser foundedUser = null;
        if (res.size() == 1) {
            foundedUser = (TaskProUser) res.get(0);
        }
        return foundedUser;
    }

    @Override
    public List<Student> getStudentByContext(Kantor kantor, Subject subject) {
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<Student> queryStudent = cb.createQuery(Student.class);
        Root<Student> rootQueryStudent = queryStudent.from(Student.class);
        Join<Student, GroupTaskPro> studentGroup = rootQueryStudent.join("mGroups");
        Predicate subjectPredicate = cb.equal(studentGroup.get("subject"), subject);
        Predicate kantorPredicate = cb.equal(studentGroup.get("kantor"), kantor);
        queryStudent.distinct(true).where(cb.and(subjectPredicate, kantorPredicate)).orderBy(cb.asc(rootQueryStudent.get("login")));
        TypedQuery typedQuery = em.createQuery(queryStudent);
        List<Student> resultList = typedQuery.getResultList();
        return resultList;

    }
    /**
     * {@inheritDoc} 
     * Not supported now!
     */
    @Override
    public List<Student> getStudentNotInTeam(GroupTaskPro group) {
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<Student> studentQuery = cb.createQuery(Student.class);
        Root<Student> rootStudentQuery = studentQuery.from(Student.class);
        Predicate studentInGroup = cb.equal(rootStudentQuery.get("mGroups"), group);
        Join<Team, Student> studentInTeam = rootStudentQuery.join("team");
        TypedQuery typedQuery = em.createQuery(studentQuery);
        List<Student> resultList = typedQuery.getResultList();
        throw new UnsupportedOperationException("not supported now");
    }
}